/*************************************************************************\
*                  Copyright (C) Michael Kerrisk, 2016.                   *
*                                                                         *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU Lesser General Public License as published   *
* by the Free Software Foundation, either version 3 or (at your option)   *
* any later version. This program is distributed without any warranty.    *
* See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details.           *
\*************************************************************************/

/* Listing 59-1 */

/* read_line.c

   Implementation of readLine().
*/
#include<fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "read_line.h"                  /* Declaration of readLine() */
#include<stdlib.h>
/* Read characters from 'fd' until a newline is encountered. If a newline
  character is not encountered in the first (n - 1) bytes, then the excess
  characters are discarded. The returned string placed in 'buf' is
  null-terminated and includes the newline character if it was read in the
  first (n - 1) bytes. The function return value is the number of bytes
  placed in buffer (which includes the newline character if encountered,
  but excludes the terminating null byte). */

ssize_t
readLine(int fd, void *buffer, size_t n)
{
    ssize_t numRead;                    /* # of bytes fetched by last read() */
    size_t totRead;                     /* Total bytes read so far */
    char *buf;
    char ch;

    if (n <= 0 || buffer == NULL) {
        errno = EINVAL;
        return -1;
    }

    buf = buffer;                       /* No pointer arithmetic on "void *" */

    totRead = 0;
    for (;;) {
        numRead = read(fd, &ch, 1);

        if (numRead == -1) {
            if (errno == EINTR)         /* Interrupted --> restart read() */
                continue;
            else
                return -1;              /* Some other error */

        } else if (numRead == 0) {      /* EOF */
            if (totRead == 0)           /* No bytes read; return 0 */
                return 0;
            else                        /* Some bytes read; add '\0' */
                break;

        } else {                        /* 'numRead' must be 1 if we get here */
            if (totRead < n - 1) {      /* Discard > (n - 1) bytes */
                totRead++;
                *buf++ = ch;
            }

            if (ch == '\n')
                break;
        }
    }

    *buf = '\0';
    return totRead;
}

// 建立一个fd对应的char*数组
// 在建立一个fd对应的buf数组
#define FD_SIZE 1024 
#define BUFFER_SIZE  4096
typedef struct FDT{
    char * buf;
    int pos;
    int num;
}Fdt;
Fdt fdt[FD_SIZE];
void readLineBufInit(int fd )
{
    fdt[fd].buf = (char *)malloc(BUFFER_SIZE);
    if( !fdt[fd].buf) 
        fatal("malloc error ");
    memset(fdt[fd].buf,0,BUFFER_SIZE);
    fdt[fd].pos = 0;
    fdt[fd].num = 0;
}
int readTrue(int fd,char * buffer,size_t n,int *jpos )
{
    int i = fdt[fd].pos ,j = *jpos;
    for(;i < fdt[fd].num && j < n ; ++ i , ++ j){
        buffer[j] = fdt[fd].buf[i];
        if(fdt[fd].buf[i] == '\n')
            break;
    }
    if(fdt[fd].buf[i] == '\n'){
        buffer[j] = '\0';
        fdt[fd].pos = i + 1;
        return j + 1;
    } 
    fdt[fd].pos = i;
    if(j == n) 
        return  n;
    *jpos = j;  // 这里的下标要一直移动
    return -1;
}
int readLineBuf(int fd,char * buffer,size_t n)
{
    int res = 0,j = 0;
    while(1){
        if((res = readTrue(fd,buffer,n,&j)) >= 0) return res ;
        int numRead = read(fd , fdt[fd].buf,BUFFER_SIZE);
        if(numRead == -1 &&errno != EINTR ) 
            errExit("read error");
        else if(numRead == 0)
            return -1;
        fdt[fd].pos = 0;
        fdt[fd].num = numRead;
    }
    return -1;
}
int  readlineQuick(int fd, void *buffer, size_t n)
{
    if(fd >= FD_SIZE || fd < 0)
        errExit("fd is illegal!");
    if(!fdt[fd].buf) 
        readLineBufInit(fd);
    int numRead = readLineBuf(fd,buffer,n);
    return numRead ;
}


int main()
{
    int fd = open("caseread" , O_RDONLY,0664);
    if(fd == -1)
        errExit("open");
    char buffer[1024] ;
    int n = 100;
    for(;readlineQuick(fd,buffer,n) != -1;){
        puts(buffer);
    }
    exit(0);
    lseek(fd,0,SEEK_SET);
    int t = clock();
    printf("readlineQuick clock is :  %d\n",t);
    for(;readLine(fd,buffer,n) > 0;){
        // puts(buffer);
    }
    printf("readline clock is :  %d\n",clock() - t);

    return 0;
}



